package cn.gwm.flink.streaming.strategy.multidimension;

import cn.gwm.flink.streaming.constant.ChargePredictFields;
import cn.gwm.flink.streaming.strategy.vehiclepredict.DwsStrConstant;
import cn.gwm.utils.HBaseDataSource;
import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.apache.flink.api.common.state.MapState;
import redis.clients.jedis.JedisCluster;

import java.io.Serializable;
import java.math.BigDecimal;
import java.sql.Connection;
import java.util.ArrayList;
import java.util.List;

/**
 * @author : GW00280745
 * @date : 2022/12/19 13:14
 * @description :
 *
 * 当前预测思路是一种猜想：如果某台车充电的 地点、soc、电压和温度 相似 ==> 那么认为充电时间大概率相等 。
 *    电流是电池根据soc、电压和温度的值进行相应的输出。
 *
 */
public class MultiDimensionTimePredictDc implements Serializable {
    public static void main(String[] args) throws Exception{
        MultiDimensionTimePredictDc timePredict = new MultiDimensionTimePredictDc();
        Connection connection = HBaseDataSource.ins().getDataSource().getConnection();
        String vinStr = "LGWEEUA52NC002466";
        String timeStr = "1674174081000";
        String socStr = "18.8";
        String currStr = "-60.8";
        String tempStr = "-1";
        String poiId = "-999999";
        String aoiId = "-999999";
        String bmsDcChrgConnect="1";
        for (int i = 0; i < 1; i++) {
            JSONObject jsonObject = new JSONObject();
            jsonObject.put("deviceId",vinStr);
            jsonObject.put("vin",vinStr);
            jsonObject.put("item_time",timeStr);
            jsonObject.put("tid",timeStr);
            jsonObject.put("startChargeTime",timeStr);
            jsonObject.put("mapId","-999999");
            jsonObject.put("bms_innersoc",socStr);
            jsonObject.put("bms_soc",socStr);
            jsonObject.put("bms_batt_curr_rm",currStr);
            jsonObject.put("bms_rmc_module_temp_min",tempStr);
            jsonObject.put("bms_rmc_moduletempmin",tempStr);
            jsonObject.put("model_code","CC7000CG00ABEV");
            jsonObject.put("bms_heatreq","0");
            jsonObject.put("acopensts","0");
            jsonObject.put("bms_dc_chrg_connect",bmsDcChrgConnect);
            jsonObject.put("poiid",poiId);
            jsonObject.put("aoiid",aoiId);
            String predict = timePredict.predictV2(jsonObject);
            System.out.println(i + ":" + predict);
        }
    }

    private String itemTimeStr = "item_time";
    private String endChargeTimeStr = "endchargetime";
    private String char3 = "#";
    private String innerSocStr = "bms_innersoc";
    private String endSocStr = "end_bms_soc";
    private String startIsNull = "start_is_null";
    private String deltaTime = "delta_time";

    private PhoenixInfo queryUtil = new PhoenixInfo();
    private PhoenixInfoDc queryUtilDc = new PhoenixInfoDc();

    public String time(JSONObject line, JedisCluster socIntervalJedis) {
        try {
            String predict = predict(line);
            if (StringUtils.isBlank(predict)) {
                return null;
            }
            //智能充电模块-数据对接 格式  charge:status:{vin}:{startChargeTime}
            intellectCharge(line, socIntervalJedis, predict);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public String time(MapState<String, String> latestEstimateState,
                       JSONObject line,
                       String chargeGroup,
                       JedisCluster socIntervalJedis) {
        try {
            String predict = predict(line);
            if (StringUtils.isBlank(predict)) {
                return null;
            }
            //配合各种state
            String[] split = predict.split(ChargePredictFields.ins().char3);
            latestEstimateState.put(ChargePredictFields.ins().stdFieldEstimateTime, split[0]);
            line.put(ChargePredictFields.ins().stdFieldEstimateTime, split[0]);
            latestEstimateState.put(ChargePredictFields.ins().stdFieldPredictTime, predict);
            line.put(ChargePredictFields.ins().stdFieldPredictTime, predict);
            latestEstimateState.put(chargeGroup, predict);
            line.put(ChargePredictFields.ins().stdFieldPredictTimeV2, predict);
            //智能充电模块-数据对接 格式  charge:status:{vin}:{startChargeTime}
            intellectCharge(line, socIntervalJedis, predict);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    public String timeV1(MapState<String, String> latestEstimateState,
                         JSONObject line,
                         String chargeGroup,
                         JedisCluster socIntervalJedis) {
        try {
            String predict = predictV2(line);
            if (StringUtils.isBlank(predict)) {
                return null;
            }
            //配合各种state
            String[] split = predict.split(ChargePredictFields.ins().char3);
            latestEstimateState.put(ChargePredictFields.ins().stdFieldEstimateTime, split[0]);
            line.put(ChargePredictFields.ins().stdFieldEstimateTime, split[0]);
            latestEstimateState.put(ChargePredictFields.ins().stdFieldPredictTime, predict);
            line.put(ChargePredictFields.ins().stdFieldPredictTime, predict);
            latestEstimateState.put(chargeGroup, predict);
            line.put(ChargePredictFields.ins().stdFieldPredictTimeV2, predict);
            //智能充电模块-数据对接 格式  charge:status:{vin}:{startChargeTime}
            intellectCharge(line, socIntervalJedis, predict);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    private String redisPrefix = "charge:status:";

    private void intellectCharge(JSONObject line, JedisCluster socIntervalJedis, String predict) {
        try {
            if (socIntervalJedis == null){
                System.out.println("socIntervalJedis is null.please check： ");
                return;
            }
            //charge:status:{vin}:{startChargeTime}
            String startChargeTime = line.getString(ChargePredictFields.ins().srcFieldStartChargeTime);
            String vinVal = line.getString(ChargePredictFields.ins().srcFieldVin);
            String key = redisPrefix.concat(vinVal).concat(ChargePredictFields.ins().colon)
                    .concat(startChargeTime);
            String s = predict.split(ChargePredictFields.ins().char3)[0];
            socIntervalJedis.set(key, s);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private String predict(JSONObject line) {
        Float bmsSoc = line.getFloat(ChargePredictFields.ins().srcFieldBmsSoc);
        JSONObject startTimeJson = startPointsOfCurve(line, bmsSoc, false);
        if (startTimeJson == null) {
            line.put(ChargePredictFields.ins().stdFieldPredictTimeV2, startIsNull);
            return null;
        }
        Long startTime = startTimeJson.getLong(itemTimeStr);
        Long endTime = startTimeJson.getLong(endChargeTimeStr);
        long totalTime = endTime - startTime;
        String endSoc = startTimeJson.getString(endSocStr);
        String concat = String.valueOf(bmsSoc).concat(char3).concat(endSoc).concat(char3);
        float innersocEnd = startTimeJson.getFloatValue(endSocStr);
        if (Math.abs(innersocEnd - endSocLimit)> DwsStrConstant.ins().num5){
            //默认预测到95
            //差的这一段需要进行补 而当前结束点的soc就是起点
//            List<JSONObject> list = endSoc(startTimeJson, innersocEnd)
//            for (JSONObject jsonObject : list) {
//                float bSoc = jsonObject.getFloatValue(innerSocStr)
//                concat = concat.concat(String.valueOf(bSoc)).concat(char3)
//                Long a = jsonObject.getLong(deltaTime)
//                totalTime += a
//            }
            JSONObject json = breakPointsOfCurve(line, innersocEnd);
            if (json != null){
                float bSoc = json.getFloatValue(endSocStr);
                concat = concat.concat(String.valueOf(bSoc)).concat(char3);
                startTime = json.getLong(itemTimeStr);
                endTime = json.getLong(endChargeTimeStr);
                long a = endTime - startTime;
                totalTime += a;
            }

        }
        int i = new BigDecimal(totalTime).divide(new BigDecimal(60 * 1000), 0, BigDecimal.ROUND_HALF_DOWN).intValue();
        String res = String.valueOf(i).concat(char3).concat(concat);
        String substring = res.substring(0, res.length() - 1);
        line.put(ChargePredictFields.ins().stdFieldPredictTimeV2,substring);
        return substring;
    }

    /**
     * 起点阶段补充策略
     * 根据起点 电流+温度 匹配某充电记录，获得该充电记录的起始阶段时间和稳定后的电流、温度
     * 根据获得的电流、温度，加上当前soc+10，匹配
     **/
    private String predictV2(JSONObject line) {
        String s = predictV3(line);
        if (StringUtils.isNotBlank(s)){
            return s;
        }
        //就是没有匹配到
        Float bmsSoc = line.getFloat(ChargePredictFields.ins().srcFieldBmsSoc);
        Float bmsCurr = line.getFloat(ChargePredictFields.ins().srcFieldBmsBatterCurrRm);
        float totalTime = 0;
        if (Math.abs(bmsCurr)<DwsStrConstant.ins().num7){
            totalTime = (99-(bmsSoc+1))*12.5f;
        }else if (Math.abs(bmsCurr)<DwsStrConstant.ins().num20){
            totalTime = (99-bmsSoc)*5f;
        }else{
            totalTime = (99-bmsSoc)*1.1f;
        }
        if (totalTime<=0){
            totalTime = 15;
        }
        String concat = String.valueOf((int) totalTime).concat(char3).concat(bmsSoc.toString()).concat(char3).concat("99");
        return concat;
    }
    private String predictV3(JSONObject line) {
        boolean isDc = StringUtils.equalsIgnoreCase(line.getString(ChargePredictFields.ins().srcFieldBmsDcConnect), "1");
        if (isDc){
            return predictV3Dc(line);
        }
        Float bmsSoc1 = line.getFloat(ChargePredictFields.ins().srcFieldBmsSoc);
//        JSONObject startStageJson = startStage(line)
        JSONObject startStageJson = startStageDc(line);
        if (startStageJson==null){
            line.put(ChargePredictFields.ins().stdFieldPredictTimeV2, startIsNull);
            return null;
        }
        long ssTime = startStageTime(startStageJson);
//        Float startTimeJson = startPointsOfCurveV1(line, startStageJson, bms_soc)
        Float startTimeJson = startPointsOfCurveV1Dc(line, startStageJson, bmsSoc1);
        long totalTime = ssTime;

//        Float startTimeJson = startPointsOfCurveV1(line, null, bms_soc)
//        long totalTime = 0
        if (startTimeJson == null) {
            line.put(ChargePredictFields.ins().stdFieldPredictTimeV2, startIsNull);
            return null;
        }
        String concat = String.valueOf(bmsSoc1).concat(char3).concat("99").concat(char3);
        int i = new BigDecimal(totalTime).divide(new BigDecimal(60 * 1000), 0, BigDecimal.ROUND_HALF_DOWN).intValue();
        i += startTimeJson;
        String res = String.valueOf(i).concat(char3).concat(concat);
        String substring = res.substring(0, res.length() - 1);
        line.put(ChargePredictFields.ins().stdFieldPredictTimeV2,substring);
        return substring;
    }
    public String predictV3Dc(JSONObject line) {
        Float bmsSoc = line.getFloat(ChargePredictFields.ins().srcFieldBmsSoc);
        Float startTimeJson = startPointsOfCurveV1Dc(line, null, bmsSoc);
        long totalTime = 0;
        if (startTimeJson == null) {
            line.put(ChargePredictFields.ins().stdFieldPredictTimeV2, startIsNull);
            return null;
        }
        String concat = String.valueOf(bmsSoc).concat(char3).concat("99").concat(char3);
//        int i = new BigDecimal(totalTime).divide(new BigDecimal(60 * 1000), 0, BigDecimal.ROUND_HALF_DOWN).intValue()
//        i += startTimeJson
        int i = new BigDecimal(startTimeJson).setScale(0,BigDecimal.ROUND_UP).intValue();
        String res = String.valueOf(i).concat(char3).concat(concat);
        String substring = res.substring(0, res.length() - 1);
        line.put(ChargePredictFields.ins().stdFieldPredictTimeV2,substring);
        return substring;
    }

    private long startStageTime(JSONObject startStageJson) {
        String steadyTime = startStageJson.getString("steady_time");
        String startChargeTime = startStageJson.getString("startChargeTime");
        long l = new BigDecimal(steadyTime).subtract(new BigDecimal(startChargeTime)).longValue();
        return l;
    }

    private JSONObject startStage(JSONObject line) {
        String startConditionCurr = queryUtil.startStageQuery(line);
        JSONObject startTimeJson = queryUtil.queryMapId(startConditionCurr,line);
        return startTimeJson;
    }
    private JSONObject startStageDc(JSONObject line) {
        String startConditionCurr = queryUtilDc.startStageQuery(line);
        JSONObject startTimeJson = queryUtilDc.queryMapId(startConditionCurr,line);
        return startTimeJson;
    }
    private String steadyCurrKey="steady_curr";
    private String steadyTempMinKey="steady_tempmin";
    private Float startPointsOfCurveV1(JSONObject line, JSONObject startTimeJson,Float bmsSoc){
        Object steadyCurr = null;
        Object steadyTempmin = null;
        if (startTimeJson!=null){
            steadyCurr = startTimeJson.get(steadyCurrKey);
            steadyTempmin = startTimeJson.get(steadyTempMinKey);
        }
        float soc = bmsSoc + 10;
        String startConditionCurr = queryUtil.startQueryV1(line,soc,steadyCurr,steadyTempmin);
//        Float v = queryUtil.queryMapId3(startConditionCurr, line, soc)
//        return v //64
        Float v = queryUtil.queryMapId4(startConditionCurr, line, soc);
//        return v // 68
        if (v==null){return v;}
        float testV = v * (100 - soc);
        //73
        return testV;
    }
    private Float startPointsOfCurveV1Dc(JSONObject line, JSONObject startTimeJson, Float bmsSoc1){
        Object steadyCurr = null;
        Object steadyTempMin = null;
        if (startTimeJson!=null){
            steadyCurr = startTimeJson.get(steadyCurrKey);
            steadyTempMin = startTimeJson.get(steadyTempMinKey);
        }
//        float soc = bms_soc + 10
        float soc = bmsSoc1;
//        String startConditionCurr = queryUtilDC.startQueryV1(line,soc,steadyCurr,steadyTempmin)
        String startConditionCurr = queryUtilDc.startDcQueryV2(line,soc,steadyCurr,steadyTempMin);
//        Float v = queryUtil.queryMapId3(startConditionCurr, line, soc)
//        return v //64
//        Float v = queryUtilDC.queryMapId4(startConditionCurr, line, soc)
        Float v = queryUtilDc.queryMapId6(startConditionCurr, line, soc);
//        return v // 68
        if (v==null){return v;}
        Float tempMin = line.getFloat(ChargePredictFields.ins().srcFieldBmsRmcModuleTempMin);
        Float bmsCurr = line.getFloat(ChargePredictFields.ins().srcFieldBmsBatterCurrRm);
        //当前策略=0.78
//        if (tempMin != null){
//            if (tempMin >= 0 && tempMin <= 5){
//                float testV = v * 1.2f * (100 - soc)
//                return testV
//            }else if(tempMin < -5  ){
//                float testV = v * 1.7f * (100 - soc)
//                return testV
//            }
//        }
        // 当前策略=0.70,0.65
//        if (tempMin != null){
//            if (tempMin >= 0 && tempMin <= 5){
//                float testV = v * 1.2f * (100 - soc)
//                return testV
//            }else if(tempMin >= -5 && tempMin < 0  ){
//                float testV = 1.5f * (100 - soc)
//                return testV
//            }else if(tempMin < -5  ){
//                float testV = 1.7f * (100 - soc)
//                return testV
//            }else if( Math.abs(bms_curr) <= 100f ){
//                float testV = 1.5f * (100 - soc)
//                return testV
//            }else if (Math.abs(bms_curr) > 100f){
////                float testV = v * 0.8f * (100 - soc)
//                float testV =  0.9f * (100 - soc)
//                return testV
//            }
//        }
        if(v>=DwsStrConstant.ins().num2){
            v=1.8f;
        }
        float testV = v  * (100 - soc);
        return testV;
    }

    private float endSocLimit = 100f;

    private JSONObject startPointsOfCurve(JSONObject line, Float bmsSoc1,boolean endSocFlag){
        JSONObject startTimeJson = null;
        if (true){
//            return startPointOfCurve(line,bms_soc,endSocFlag)
        }
        //如果没有相匹配的开始点 可能是 1.该辆车的第一次充电记录 2.就是没有对应的点
        //放大电流和地点条件 一般慢充有两种 一个是8A 一个是18A，放大电流条件那么就意味着都囊括进来了。同时将地点也放大
        String startConditionCurr = queryUtil.startObcCurr(line,bmsSoc1,endSocFlag,false,5,false,false);
        startTimeJson = queryUtil.queryMapId(startConditionCurr,line);
        if (startTimeJson == null){
            //同一辆车
            startConditionCurr = queryUtil.startObcTemp(line,bmsSoc1,endSocFlag,false,5,false,false);
            startTimeJson = queryUtil.query(startConditionCurr);
            if (startTimeJson == null){
                //查其他车的数据
//                startConditionCurr = queryUtil.startObcCurrVehicle(line,bms_soc,endSocFlag,false)
//                startTimeJson = queryUtil.queryMapId(startConditionCurr,line)
            }
        }
        //如果还是null 那可能是找不到了
        return startTimeJson;
    }
    private JSONObject breakPointsOfCurve(JSONObject line, Float bmsSoc){
        String startConditionCurr = queryUtil.startObcCurr(line,bmsSoc,false,false,5,false,true);
        JSONObject startTimeJson = queryUtil.queryMapId(startConditionCurr,line);
        return startTimeJson;
    }
    private JSONObject breakPointsOfCurve1(JSONObject line, Float bmsSoc){
//        bms_soc = bms_soc - 5
        String startConditionCurr = queryUtil.startObcCurr(line,bmsSoc,false,false,5,false,true);
        JSONObject startTimeJson = queryUtil.queryMapId(startConditionCurr,line);
        return startTimeJson;
    }
    private JSONObject endPointOfCurve(JSONObject startTimeJson){
        //找到开始点所在曲线(即充电过程)的结束点
        String endCondition = queryUtil.endSoc(startTimeJson);
        JSONObject endTimeJson = queryUtil.query(endCondition);
        return endTimeJson;
    }

    private List<JSONObject> endSoc(JSONObject endTimeJson, float innerSocEnd){
        ArrayList<JSONObject> list = new ArrayList<>();
        int i = 0;
        //如果三次查询还是小于95 先暂停 找到具体数据后进行分析并修正
        float tmp = innerSocEnd;
        while (innerSocEnd < DwsStrConstant.ins().num97f && i<DwsStrConstant.ins().num3){
            JSONObject startTimeJson2 = startPointsOfCurve(endTimeJson,innerSocEnd,true);
            if (startTimeJson2 == null){
                break;
            }
            JSONObject endTimeJson2 = endPointOfCurve(startTimeJson2);
            if (endTimeJson2 == null){
                break;
            }
            Long a = startTimeJson2.getLong(itemTimeStr);
            Long b = endTimeJson2.getLong(itemTimeStr);
            long l = b - a;
            endTimeJson2.put(deltaTime,l);
            list.add(endTimeJson2);
            //下一轮 变量赋值
            endTimeJson = endTimeJson2;
            innerSocEnd = endTimeJson2.getFloatValue(innerSocStr);
            i++;
            float abs = Math.abs(innerSocEnd - tmp);
            if (abs==0){
                //当前soc和上次soc一样
                System.out.println("末端没有合适的数据可匹配了");
                break;
            }
            tmp = innerSocEnd;
        }
        return list;
    }
}
